package com.zhss.demo.register.server;


import java.util.LinkedList;
import java.util.Map;

/**
 * 服务注册中心接口从客户端发送过来的注册请求和心跳请求
 */
public class RegisterServerController {

    /**
     *获取注册表对象
     */
    private ServiceRegistry registry = ServiceRegistry.getInstance();

    /**
     * 服务注册表的缓存
     */
    private ServiceRegistryCache registryCache = ServiceRegistryCache.getInstance();

    /**
     * 服务注册
     * @param registerRequest 注册请求
     * @return 注册响应
     */
    public RegisterResponse register(RegisterRequest registerRequest) {
        RegisterResponse registerResponse = new RegisterResponse();

        try {
            // 这里创建一个注册表，同时也创建了一个续约类
            ServiceInstance serviceInstance = new ServiceInstance();
            serviceInstance.setHostname(registerRequest.getHostname());
            serviceInstance.setIp(registerRequest.getIp());
            serviceInstance.setPort(registerRequest.getPort());
            serviceInstance.setServiceInstanceId(registerRequest.getServiceInstanceId());
            serviceInstance.setServiceName(registerRequest.getServiceName());
            // 注册服务,这里服务注册成功之后不仅会将该实例写入注册表中，同时还会把该实例作为注册事件放入增量队列中
            registry.register(serviceInstance);
            // 更新自我保护机制阈值
            synchronized(SelfProtectionPolicy.class) {
                SelfProtectionPolicy selfProtectionPolicy = SelfProtectionPolicy.getInstance();
                selfProtectionPolicy.setExpectedHeartbeatRate(selfProtectionPolicy.getExpectedHeartbeatRate() + 2);
                selfProtectionPolicy.setExpectedHeartbeatThreshold((long)(selfProtectionPolicy.getExpectedHeartbeatRate() * 0.85));
            }
            // 过期掉注册表缓存
            registryCache.invalidate();
            registerResponse.setStatus(RegisterResponse.SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            registerResponse.setStatus(RegisterResponse.FAILURE);
        }
        return registerResponse;
    }

    /**
     * 发送心跳
     * @param heartbeatRequest 心跳请求
     * @return 心跳响应
     */
    public HeartbeatResponse heartbeat(HeartbeatRequest heartbeatRequest) {
        // 获取像心跳结果返回
        HeartbeatResponse heartbeatResponse = new HeartbeatResponse();
        try {
            // 从注册表中获取服务的注册信息
            ServiceInstance serviceInstance = registry.getServiceInstance(
                    heartbeatRequest.getServiceName(),
                    heartbeatRequest.getServiceInstanceId());
            if(serviceInstance != null) {
                // 对于当前服务进行一次续约
                serviceInstance.renew();
            }
            // 记录一下每分钟的心跳的次数
            HeartbeatCounter heartbeatMessuredRate = HeartbeatCounter.getInstance();
            heartbeatMessuredRate.increment();
            // 设置续约成功返回状态
            heartbeatResponse.setStatus(HeartbeatResponse.SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            heartbeatResponse.setStatus(HeartbeatResponse.FAILURE);
        }

        return heartbeatResponse;
    }

    /**
     * 服务下线请求
     * @param serviceName       服务名称
     * @param serivceInstanceId 服务实例id
     */
    public void cancle(String serviceName, String serivceInstanceId) {
        // 服务下线之后期望的心跳次数应该要减2
        synchronized(SelfProtectionPolicy.class) {
            SelfProtectionPolicy selfProtectionPolicy = SelfProtectionPolicy.getInstance();
            selfProtectionPolicy.setExpectedHeartbeatRate(selfProtectionPolicy.getExpectedHeartbeatRate() - 2);
            selfProtectionPolicy.setExpectedHeartbeatThreshold(
                    (long)(selfProtectionPolicy.getExpectedHeartbeatRate() * 0.85));
        }
        // 这里服务下线之后，除了将服务实例从注册表中移除，还会生成一个remove事件放入增量队列中
        registry.remove(serviceName,serivceInstanceId);
        // 过期掉注册表缓存
        registryCache.invalidate();
    }

    /**
     * 拉取全量注册表
     * @return
     */
    public Applications fetchFullRegistry() {
     /*   try {
            registry.readLock();
            return new Applications(registry.getRegistry());
        } finally {
            registry.unReadLock();
        }*/
        return (Applications) registryCache.get(ServiceRegistryCache.CacheKey.FULL_SERVICE_REGISTRY);
    }

    /**
     * 拉取增量注册表
     * @return
     */
    public DeltaRegistry fetchDeltaRegistry() {
/*        try {
            registry.readLock();
            return registry.getDeltaRegistry();
        } finally {
            registry.unReadLock();
        }*/
        return (DeltaRegistry) registryCache.get(ServiceRegistryCache.CacheKey.DELTA_SERVICE_REGISTRY);
    }
}
